# -*- coding: utf-8 -*-
"""
Pytest 配置文件

提供测试夹具、配置和公共测试工具。
"""

import os
import pytest
import asyncio
from typing import Generator, Dict, Any
from unittest.mock import Mock, patch

from src.mysql_mcp_server.config import Config, DatabaseConfig, LogConfig, MCPConfig
from src.mysql_mcp_server.database import DatabaseManager
from src.mysql_mcp_server.server import MySQLMCPServer


@pytest.fixture(scope="session")
def event_loop():
    """
    创建事件循环夹具
    
    用于支持异步测试。
    """
    loop = asyncio.new_event_loop()
    yield loop
    loop.close()


@pytest.fixture
def test_config() -> Config:
    """
    测试配置夹具
    
    Returns:
        Config: 测试用配置对象
    """
    return Config(
        database=DatabaseConfig(
            host="localhost",
            port=3306,
            user="test_user",
            password="test_password",
            database="test_db",
            charset="utf8mb4",
            ssl_disabled=True,
            pool_size=5,
            connection_timeout=10,
            autocommit=True
        ),
        log=LogConfig(
            level="DEBUG",
            format="text",
            file=None
        ),
        mcp=MCPConfig(
            name="test-mysql-mcp",
            version="1.0.0",
            description="Test MySQL MCP Server"
        )
    )


@pytest.fixture
def mock_database_config() -> DatabaseConfig:
    """
    模拟数据库配置夹具
    
    Returns:
        DatabaseConfig: 模拟数据库配置
    """
    return DatabaseConfig(
        host="mock_host",
        port=3307,
        user="mock_user",
        password="mock_password",
        database="mock_db",
        charset="utf8mb4",
        ssl_disabled=True,
        pool_size=3,
        connection_timeout=5,
        autocommit=False
    )


@pytest.fixture
def mock_database_manager(mock_database_config) -> Mock:
    """
    模拟数据库管理器夹具
    
    Args:
        mock_database_config: 模拟数据库配置
        
    Returns:
        Mock: 模拟的数据库管理器
    """
    mock_manager = Mock(spec=DatabaseManager)
    mock_manager.config = mock_database_config
    mock_manager.is_connected = False
    mock_manager.pool = None
    
    # 模拟方法
    mock_manager.connect.return_value = None
    mock_manager.disconnect.return_value = None
    mock_manager.execute_query.return_value = [{"result": "success"}]
    mock_manager.execute_update.return_value = 1
    mock_manager.get_database_info.return_value = {
        "version": "8.0.0",
        "tables": ["test_table1", "test_table2"]
    }
    
    return mock_manager


@pytest.fixture
def mock_mcp_server(test_config) -> Mock:
    """
    模拟 MCP 服务器夹具
    
    Args:
        test_config: 测试配置
        
    Returns:
        Mock: 模拟的 MCP 服务器
    """
    mock_server = Mock(spec=MySQLMCPServer)
    mock_server.config = test_config
    mock_server.database_manager = None
    mock_server.is_running = False
    
    # 模拟方法
    mock_server.start.return_value = None
    mock_server.stop.return_value = None
    mock_server.run.return_value = None
    
    return mock_server


@pytest.fixture
def sample_database_data() -> Dict[str, Any]:
    """
    示例数据库数据夹具
    
    Returns:
        Dict[str, Any]: 示例数据
    """
    return {
        "users": [
            {"id": 1, "name": "Alice", "email": "alice@example.com", "age": 25},
            {"id": 2, "name": "Bob", "email": "bob@example.com", "age": 30},
            {"id": 3, "name": "Charlie", "email": "charlie@example.com", "age": 35}
        ],
        "products": [
            {"id": 1, "name": "Laptop", "price": 999.99, "category": "Electronics"},
            {"id": 2, "name": "Book", "price": 19.99, "category": "Education"},
            {"id": 3, "name": "Coffee", "price": 4.99, "category": "Food"}
        ]
    }


@pytest.fixture
def mock_mysql_connection():
    """
    模拟 MySQL 连接夹具
    
    Returns:
        Mock: 模拟的 MySQL 连接对象
    """
    from unittest.mock import MagicMock
    
    mock_connection = Mock()
    mock_cursor = MagicMock()
    
    # 配置游标行为
    mock_cursor.fetchall.return_value = [{"test": "data"}]
    mock_cursor.fetchone.return_value = {"test": "data"}
    mock_cursor.rowcount = 1
    mock_cursor.description = [("test", None, None, None, None, None, None)]
    
    # 配置连接行为
    mock_connection.cursor.return_value = mock_cursor
    mock_connection.is_connected.return_value = True
    mock_connection.commit.return_value = None
    mock_connection.rollback.return_value = None
    
    return mock_connection


@pytest.fixture
def mock_connection_pool():
    """
    模拟连接池夹具
    
    Returns:
        Mock: 模拟的连接池对象
    """
    mock_pool = Mock()
    mock_connection = Mock()
    
    # 配置连接池行为
    mock_pool.get_connection.return_value = mock_connection
    mock_pool.pool_name = "test_pool"
    mock_pool.pool_size = 5
    
    return mock_pool


@pytest.fixture(autouse=True)
def setup_test_environment():
    """
    设置测试环境夹具
    
    自动应用于所有测试，用于设置测试环境变量和清理。
    """
    # 设置测试环境变量
    test_env = {
        "MYSQL_HOST": "localhost",
        "MYSQL_PORT": "3306",
        "MYSQL_USER": "test_user",
        "MYSQL_PASSWORD": "test_password",
        "MYSQL_DATABASE": "test_db",
        "LOG_LEVEL": "DEBUG",
        "LOG_FORMAT": "text"
    }
    
    # 保存原始环境变量
    original_env = {}
    for key, value in test_env.items():
        original_env[key] = os.environ.get(key)
        os.environ[key] = value
    
    yield
    
    # 恢复原始环境变量
    for key, value in original_env.items():
        if value is None:
            os.environ.pop(key, None)
        else:
            os.environ[key] = value


@pytest.fixture
def temp_config_file(tmp_path):
    """
    临时配置文件夹具
    
    Args:
        tmp_path: pytest 提供的临时路径
        
    Returns:
        Path: 临时配置文件路径
    """
    config_content = """
# 测试配置文件
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=test_user
MYSQL_PASSWORD=test_password
MYSQL_DATABASE=test_db
LOG_LEVEL=DEBUG
LOG_FORMAT=text
    """.strip()
    
    config_file = tmp_path / ".env.test"
    config_file.write_text(config_content)
    
    return config_file


# 测试标记
pytestmark = [
    pytest.mark.asyncio,  # 默认支持异步测试
]


# 测试配置
def pytest_configure(config):
    """
    Pytest 配置函数
    
    Args:
        config: pytest 配置对象
    """
    # 注册自定义标记
    config.addinivalue_line(
        "markers", "unit: 单元测试标记"
    )
    config.addinivalue_line(
        "markers", "integration: 集成测试标记"
    )
    config.addinivalue_line(
        "markers", "slow: 慢速测试标记"
    )
    config.addinivalue_line(
        "markers", "database: 需要数据库的测试标记"
    )